package com.netx.ebs;
import java.util.Random;

/*
 * This code was borrowed from Apache's commons.sandbox.id project.
 * The code is modified and the copyright is not included because
 * this is meant to be used temporarialy, only while this package is
 * not released by Apache.
 */

/**
 * <p><code>SessionIdGenerator</code> is an identifier generator
 * that generates an alphanumeric 10+ character identifier. The
 * exact length depends on the number of ids requested per time period.</p>
 *
 * <p>Originally designed for JServ sessions. Uses synchronized count and
 * time to ensure uniqueness. Not guaranteed unique across JVMs, but
 * fairly safe nonetheless.</p>

 * @author Commons-Id team
 * @version $Id: SessionIdGenerator.java,v 1.4 2004/03/17 11:51:22 psteitz Exp $
 */
class SessionIdGenerator {

    // Default size of an alphanumeric identifier
    private static final int DEFAULT_ALPHANUMERIC_IDENTIFIER_SIZE = 15;
    // Number of alphanumeric characters
    private static final int ALPHA_NUMERIC_CHARSET_SIZE = 36;

    // We want to have a random string with a length of 6 characters.
    // Since we encode it base-36, we modulo the random number with
    // this value.
    private static final long MAX_RANDOM_LEN = 2176782336L; // 36 ** 6
    
    /**
     * <p>The identifier must be unique within the typical lifespan of a
     * session; the value can roll over after that.</p>3 characters:
     * (this means a roll over after over a day, which is much larger
     * than a typical lifespan).
     */
    private static final long MAX_TIME_SECTION_LEN = 46656L; // 36 ** 3

    /**
     * Milliseconds between different tics.  The 3-character time
     * string has a new value every 2 seconds.
     */
    private static final long TIC_DIFFERENCE = 2000;

    // Maximum length for an alphanumeric string representing an integer value
    protected static final int MAX_INT_ALPHANUMERIC_VALUE_LENGTH =
    Integer.toString(Integer.MAX_VALUE, ALPHA_NUMERIC_CHARSET_SIZE).length();
    
    /**
     * Length of random segment
     */
    private static final int RANDOM_LENGTH = 6;
    /**
     * Length of time segment
     */
    private static final int TIME_LENGTH = 3;

    /** The incrementing counter. */
    private int counter = 0;
    /** The last time. */
    private long lastTimeValue = 0;
    /** The randmonizer. */
    private Random randomizer = new Random();

    /**
     * <p>Constructor.</p>
     */
    public SessionIdGenerator() {
        super();
    }

    /**
     * <p>Gets the next new identifier.</p>
     *
     * <p>Only guaranteed unique within this JVM, but fairly safe
     * for cross JVM usage as well.</p>
     *
     * <p>Format of identifier is
     * <code>[6 chars random][3 chars time][1+ chars count]</code></p>
     *
     * @return the next 10 char String identifier
     */
    public String nextStringIdentifier() {

        // Random value
        //--------------
        long currentRandom = randomizer.nextLong();
        if (currentRandom < 0) {
            currentRandom = -currentRandom;
        }
        // force value into 6 char range, and add to pad with zeros
        // this gives a length of 7, when converted to base 36, and
        // the first character (always 1 from the add) is dropped
        currentRandom %= MAX_RANDOM_LEN;
        currentRandom += MAX_RANDOM_LEN;

        long currentTimeValue = 0;
        int currentCount = 0;

        synchronized (this) {
            // Time
            //--------------
            currentTimeValue = (System.currentTimeMillis() / TIC_DIFFERENCE);

            // force value into 3 char range, and add to pad with zeros
            // this gives a length of 4, when converted to base 36, and
            // the first character (always 1 from the add) is dropped
            currentTimeValue %= MAX_TIME_SECTION_LEN;
            currentTimeValue += MAX_TIME_SECTION_LEN;

            // Count
            //--------------
            // Make the string unique by appending the count since last
            // time flip.

            // Count sessions only within tics (so the 'real' counter
            // isn't exposed to the public).
            if (lastTimeValue != currentTimeValue) {
                lastTimeValue = currentTimeValue;
                counter = 0;
            }
            currentCount = counter++;
        }

        // build string
        //--------------
        StringBuilder id = new StringBuilder
            (DEFAULT_ALPHANUMERIC_IDENTIFIER_SIZE);
        id.append(Long.toString(currentRandom,
            ALPHA_NUMERIC_CHARSET_SIZE).substring(1));  // 6 chars
        id.append(Long.toString(currentTimeValue,
            ALPHA_NUMERIC_CHARSET_SIZE).substring(1));  // 3 chars
        id.append(Long.toString(currentCount,
            ALPHA_NUMERIC_CHARSET_SIZE));  // 1+ chars
        return id.toString();
    }

    /**
     * <p>Returns the maximum length (number or characters) for an identifier
     * from this generator.</p>
     *
     * @return the maximum identifier length
     */
    public long maxLength() {
        return RANDOM_LENGTH + TIME_LENGTH
            + MAX_INT_ALPHANUMERIC_VALUE_LENGTH;
    }

    /**
     * <p>Returns the minimum length (number of characters) for an identifier
     * from this generator.</p>
     *
     * @return the minimum identifier length
     */
    public long minLength() {
        return RANDOM_LENGTH + TIME_LENGTH + 1;
    }
}

/*
    // Constant representing unlimited identifier length, returned by {@link #maxLength()}
    // when there is no upper bound to the length of an identifier in the sequence
    public static final int INFINITE_MAX_LENGTH = -1;

	// Maximum length for a numeric string representing a long value
    protected static final int MAX_LONG_NUMERIC_VALUE_LENGTH =
    Long.toString(Long.MIN_VALUE).length();

    // Maximum length for an alphanumeric string representing a long value
    protected static final int MAX_LONG_ALPHANUMERIC_VALUE_LENGTH =
    Long.toString(Long.MAX_VALUE, ALPHA_NUMERIC_CHARSET_SIZE).length();

    // Maximum length for a numeric string representing an integer value
    protected static final int MAX_INT_NUMERIC_VALUE_LENGTH =
    Integer.toString(Integer.MIN_VALUE).length();


*/
